﻿using System;
using MultiAgents;
using System.Collections.Generic;
using Mogre;

namespace MultiAgents
{
    public class Program
    {
        private View view;
        private Random _random;
        private int _numOgresDebut; //Nombre d'ogres au début de la simulation
        private int _numRobotsDebut; //Nombre de robots au début
        private int _pvDefautOgre;
        private List<Ogre> listOgre;
        private List<Robot> listRobot;
        private int _maxposition;

        /************************************************************************/
        /* program starts here                                                  */
        /************************************************************************/
        [STAThread]
        static void Main()
        {
            // create main program
            Program prg = new Program(20, 20, 10); /*utilisation _numOgres, _numRobots initialisés possible*/
            if(prg!=null) {

                prg.CreateScene(prg);

            // run engine main loop until the window is closed
                while (prg.isRunning())
                {
                    /* bouger */
                    for(int i=0; i<prg.listOgre.Count;++i)
                    {
                        prg.listOgre[i].move();
                    }
                    for (int i = 0; i < prg.listRobot.Count; ++i)
                    {
                        prg.listRobot[i].move();
                    }

                    System.Threading.Thread.Sleep(75);

                    // update the objects in the scene
                    prg.Update();
                }
            }
        }

        public List<Agent> isCollisioning(Agent A)
        {
            List<Agent> Lr = new List<Agent>();
            
            foreach (Ogre Ogr in listOgre)
            {
                if ((A.dist(A.getPosition(), Ogr.getPosition()) < (A.getdistance() + Ogr.getdistance())) && (A != Ogr))
                {
                    Lr.Add(Ogr);
                }
            }

            foreach (Robot Rob in listRobot)
            {
                if ((A.dist(A.getPosition(), Rob.getPosition()) < (A.getdistance() +Rob.getdistance())) && (A != Rob))
                {
                    Lr.Add(Rob);
                }               
            }
            return Lr;
        }

        public Vector3 directionOgre(Agent A)
        {
            double dmin = (double)Agent.MAX_DISTANCE + 1;//équivaut à l'infini du point de vu de la représentation sphérique de l'environnement

            Vector3 directionOgremin= new Vector3();
            double temp;//contiendra les distance entre l'agent et l'ogre en cours

            foreach (Ogre Ogr in listOgre)
            {
                if(Ogr != A){
                    temp=dist(Ogr.getPosition(), A.getPosition());
                    if (dmin > temp)
                    {
                        directionOgremin = Ogr.getDirection();
                        dmin = temp;
                    }
                }
            }

            /*vectoriellement: Agent + direction_cherchée = Ogre. donc direction=ogre-agent*/
            Vector3 direction = new Vector3(directionOgremin.x - A.getx(), directionOgremin.y - A.gety(), directionOgremin.z - A.getz());
            direction.Normalise();

            /*si l'agent est déjà à portée d'un ogre, il n'a pas besoin de bouger.*/
            if (dmin < A.getdistance())
            {
                direction = Vector3.ZERO;
                Console.WriteLine("Pas besoin de se déplacer, ogre à portée");
            }

            return direction;
        }
        
        public double dist(Vector3 vec, Vector3 vec2)
        {
            return System.Math.Sqrt(System.Math.Pow((vec.x - vec2.x), 2) +
                                     System.Math.Pow((vec.y - vec2.y), 2) +
                                     System.Math.Pow((vec.z - vec2.z), 2));
        }


        public bool isRunning()
        {
            return view.isRunning();
        }

        /************************************************************************/
        /* constructor                                                          */
        /************************************************************************/
        public Program(int numRobots, int numOgres, int pvDef)
        {
            view = new View();
            _random = new Random();
            _numOgresDebut = numOgres;
            _numRobotsDebut = numRobots;
            _pvDefautOgre = pvDef;
        }

        private void Update()
        { 
             view.UpdateView(listOgre, listRobot);
        }

        /************************************************************************/
        /* create a scene to render                                             */
        /************************************************************************/
        public void CreateScene(Program prg)
        {
            int max_positionxyz= (int) (Agent.MAX_DISTANCE/System.Math.Sqrt(3));//en faire un attribut de prg?-> prg._maxposition
            prg._maxposition = (int)(Agent.MAX_DISTANCE /System.Math.Sqrt(3));//Todo: check, virer le truc ligne du dessus?

            //create the non-graphical agents
            listOgre = new List<Ogre>();
            listRobot = new List<Robot>();

            for(int j =0; j<_numOgresDebut;j++)
            {
                listOgre.Add(new Ogre(prg, _random, _random.Next(-max_positionxyz, max_positionxyz),
                                                    _random.Next(-max_positionxyz, max_positionxyz),
                                                    _random.Next(-max_positionxyz, max_positionxyz), _pvDefautOgre));
            }

            for (int k = 0; k < _numRobotsDebut;k++)
            {
               listRobot.Add(new Robot(prg, _random, _random.Next(-max_positionxyz, max_positionxyz),
                                                    _random.Next(-max_positionxyz, max_positionxyz),
                                                    _random.Next(-max_positionxyz, max_positionxyz)));
            }
            
            view.CreateView(listOgre, listRobot);
        }

        public void addOgre(int pvEnfant, Vector3 pos)
        {
            /*créer un nouvel ogre dans la liste, ayant comme pv ceux passés en param*/
            listOgre.Add(new Ogre(this, _random, pos.x, pos.y, pos.z, pvEnfant));
        }

        internal void killMe(Ogre ogre)
        {
            listOgre.Remove(ogre);
        }
    } // class

} // namespace
